/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/*******************************************************************************
    FILE NAME:		ecanlib.cc

    PROJECT:		Linux ECAN527/1000 driver, library, and sample programs

    FILE DESCRIPTION:	Source code for ECAN 527/1000 library routines.

    Copyright (c) 2004 RTD Embedded Technologies, Inc.

    For driver version, compiler, and target information, please refer to the
    file README.TXT.
*******************************************************************************/

#ifdef LINUX_OS
# ifndef __cplusplus
#  error C++ compiler needed for this source
# endif

#include <stdio.h>	// sprintf()

#ifdef LINUX_OS
#include <ecanlib.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>	// open()
#include <sys/types.h>
#endif

#include <inttypes.h>


/******************************************************************************
EncodeMessageID()

    Purpose:


    Parameters:

    Return Value:
        None.
 ******************************************************************************/

static void
EncodeMessageID(
    uint8_t *ID0,
    uint8_t *ID1,
    uint8_t *ID2,
    uint8_t *ID3,
    bool Extended
) {
    uint8_t	Byte0 = *ID0;
    uint8_t	Byte1 = *ID1;
    uint8_t	Byte2 = *ID2;
    uint8_t	Byte3 = *ID3;

    if (! Extended) {
	uint8_t	Temp0 = ((Byte1 & 0xf8) >> 3);
	uint8_t	Temp1 = ((Byte1 & 7) << 5);

	Temp0 |= ((Byte0 & 7) << 5);

	*ID0 = Temp0;
	*ID1 = Temp1;
	*ID2 = 0;
	*ID3 = 0;
    } else {
	uint8_t	Temp0 = ((Byte1 & 0xE0) >> 5);
	uint8_t	Temp1 = ((Byte2 & 0xE0) >> 5);
	uint8_t	Temp2 = ((Byte3 & 0xE0) >> 5);
	uint8_t	Temp3 = ((Byte3 & 0x1f) << 3);

	Temp0 |= ((Byte0 & 0x1f) << 3);
	Temp1 |= ((Byte1 & 0x1f) << 3);
	Temp2 |= ((Byte2 & 0x1f) << 3);

	*ID0 = Temp0;
	*ID1 = Temp1;
	*ID2 = Temp2;
	*ID3 = Temp3;
    }
}


/* returns 0 or -1 on errors (see errno) */
int rtd_ecan_clear_accounts(int handle)
{
    return ioctl(handle, __RTD_ECAN_IOCTL__CLEAR_ACCOUNTS);
}


/* returns 0 or -1 on errors (see errno) */
int rtd_ecan_get_accounts(int handle, rtd_ecan_accounts_t *accounts_p)
{
    return ioctl(handle, __RTD_ECAN_IOCTL__GET_ACCOUNTS, accounts_p);
}


/* Returns driver's version (100 or 200 etc) */
/* or -1 on errors (see errno)               */
ssize_t rtd_ecan_get_driver_version(int handle)
{
    return ioctl(handle, __RTD_ECAN_IOCTL__GET_DRIVER_VERSION);
}


/* Get board's type name (a positive number)               */
/* returns board's type number or -1 on errors (see errno) */
ssize_t rtd_ecan_get_board_name(int handle)
{
    return ioctl(handle, __RTD_ECAN_IOCTL__GET_BOARD_NAME);
}


/* hardware-specific values provided by user */
/* returns 0 or -1 on errors (see errno)     */
int rtd_ecan_set_bus_config(
    int handle,
    u8_t BusTiming0,
    u8_t BusTiming1,
    u8_t ClockOut,
    u8_t BusConfig
) {
    struct __rtd_ecan_ioctl_busconfig arg =
	{BusTiming0, BusTiming1, ClockOut, BusConfig};

    return ioctl(handle, __RTD_ECAN_IOCTL__SET_BUS_CONFIG, &arg);
}


/* returns 0 or -1 on errors (see errno) */
int rtd_ecan_send_command(
    int handle,
    const struct rtd_ecan_send_command *command_p
) {
    return ioctl(handle, __RTD_ECAN_IOCTL__SEND_COMMAND, command_p);
}


/* Set LEDs                              */
/* returns 0 or -1 on errors (see errno) */
int rtd_ecan_set_leds(int handle, uint led_flags)
{
    return ioctl(handle, __RTD_ECAN_IOCTL__SET_LEDS, led_flags);
}


/* Get CAN controller's RAM area into user's buffer.               */
/* Returns 0 on success, -1 on errors (see errno).                  */
int rtd_ecan_get_ram(
    int handle,
    size_t ram_offset,
    size_t ram_len,
    void *buffer_p
) {
    struct __rtd_ecan_ioctl_get_ram arg = {ram_offset, ram_len, buffer_p};

    return ioctl(handle, __RTD_ECAN_IOCTL__GET_RAM, &arg);
}


/* Set CAN controller's RAM area from user's buffer.                */
/* Returns 0 on success, -1 on errors (see errno).                  */
int rtd_ecan_set_ram(
    int handle,
    size_t ram_offset,
    size_t ram_len,
    const void *buffer_p
) {
    struct __rtd_ecan_ioctl_set_ram arg = {ram_offset, ram_len, buffer_p};

    return ioctl(handle, __RTD_ECAN_IOCTL__SET_RAM, &arg);
}


/* Set receive queue size                */
/* Clears queue contents (compatibility) */
/* Returns 0 or -1 on errors (see errno) */
int rtd_ecan_set_rx_max_queue_size(int handle, size_t max_queue_size)
{
    return ioctl(
	handle,
	__RTD_ECAN_IOCTL__SET_RX_MAX_QUEUE_SIZE,
	max_queue_size
    );
}


/* Set transmit queue size               */
/* Clears queue contents (compatibility) */
/* Returns 0 or -1 on errors (see errno) */
int rtd_ecan_set_tx_max_queue_size(int handle, size_t max_queue_size)
{
    return ioctl(
	handle,
	__RTD_ECAN_IOCTL__SET_TX_MAX_QUEUE_SIZE,
	max_queue_size
    );
}


/* returns 0 or -1 on errors (see errno) */
int rtd_ecan_clear_queues(int handle, uint queue_flags)
{
    return ioctl(handle, __RTD_ECAN_IOCTL__CLEAR_QUEUES, queue_flags);
}


/* Get queue counts */
/* returns 0 or -1 on errors (see errno) */
int rtd_ecan_get_queues_counts(
    int handle,
    size_t *rx_count_p,
    size_t *tx_count_p
) {
    struct __rtd_ecan_ioctl_queues_counts arg;
    int rc;

    rc = ioctl(handle, __RTD_ECAN_IOCTL__GET_QUEUES_COUNTS, &arg);
    *rx_count_p = arg.rx_queue_count;
    *tx_count_p = arg.tx_queue_count;
    return rc;
}


/* Set re-set mode                       */
/* returns 0 or -1 on errors (see errno) */
int rtd_ecan_stop(int handle)
{
    return ioctl(handle, __RTD_ECAN_IOCTL__STOP);
}


/* Set operating mode                    */
/* returns 0 or -1 on errors (see errno) */
int rtd_ecan_start(int handle)
{
    return ioctl(handle, __RTD_ECAN_IOCTL__START);
}


/* Testing of ECAN board                 */
/* returns 0 or -1 on errors (see errno) */
int rtd_ecan_test(int handle)
{
    return ioctl(handle, __RTD_ECAN_IOCTL__TEST);
}



/* Prepare received message for access by successive calls        */
/* Get message interrupt bits and current receive queue size      */
/* Returns 0 or -1 on errors (see errno)                          */
int rtd_ecan_prepare_received_message(
    int handle,
    uint *events_p,
    size_t *rx_queue_count_p,
    int dont_use_queue
) {
    int rc;
    struct __rtd_ecan_ioctl_prepare_received_message arg;

    rc = ioctl(
	handle,
	__RTD_ECAN_IOCTL__PREPARE_RECEIVED_MESSAGE
	| (dont_use_queue?__RTD_ECAN_DONT_USE_QUEUE:0),
	&arg
    );

    *events_p         = arg.events;
    *rx_queue_count_p = arg.rx_queue_count;

    return rc;
}


/* returns 0 or -1 on errors (see errno) */
int rtd_ecan_get_status(
    int handle,
    struct rtd_ecan_status *status_p,
    int dont_use_queue
) {
    return ioctl(
	handle,
	__RTD_ECAN_IOCTL__GET_STATUS
	| (dont_use_queue?__RTD_ECAN_DONT_USE_QUEUE:0),
	status_p
    );
}


/* returns 0 or -1 on errors (see errno) */
int rtd_ecan_recv_message(
    int handle,
    struct rtd_ecan_message *message_p,
    int dont_use_queue
) {
    return ioctl(
	handle,
	__RTD_ECAN_IOCTL__RECV_MESSAGE
	| (dont_use_queue?__RTD_ECAN_DONT_USE_QUEUE:0),
	message_p
    );
}


/* returns 0 or -1 on errors (see errno) */
int rtd_ecan_send_message(
    int handle,
    struct rtd_ecan_message *message_p,
    int dont_use_queue
) {
    return ioctl(
	handle,
	__RTD_ECAN_IOCTL__SEND_MESSAGE
	| (dont_use_queue?__RTD_ECAN_DONT_USE_QUEUE:0),
	message_p
    );
}


/* ECAN527 only                              */
/* returns 0 or -1 on errors (see errno)     */
int rtd_ecan_setup_message_object(
    int handle,
    const struct rtd_ecan_msg_obj_setup *object_p,
    int dont_use_queue
) {
    return ioctl(
	handle,
	__RTD_ECAN_IOCTL__SETUP_MESSAGE_OBJECT
	| (dont_use_queue?__RTD_ECAN_DONT_USE_QUEUE:0),
	object_p
    );
}


/* returns 0 or -1 on errors (see errno) */
int rtd_ecan_set_filter(
    int handle,
    const struct rtd_ecan_filter *filter_p,
    int dont_use_queue
) {
    return ioctl(
	handle,
	__RTD_ECAN_IOCTL__SET_FILTER
	| (dont_use_queue?__RTD_ECAN_DONT_USE_QUEUE:0),
	filter_p
    );
}


/* Set interrupt enable bits             */
/* returns 0 or -1 on errors (see errno) */
int rtd_ecan_set_events_mask(int handle, uint events_mask)
{
    return ioctl(handle, __RTD_ECAN_IOCTL__SET_EVENTS_MASK, events_mask);
}


/* Hack: use O_SYNC open flag to prevent driver from extra board operations
   on open and close */


int rtd_ecan_read_digital_io(int device_handle, unsigned char *digital_data_p) {
    return ioctl(
	device_handle,
	__RTD_ECAN_IOCTL__READ_DIGITAL_IO,
	digital_data_p
    );
}


int rtd_ecan_write_digital_io(int device_handle, unsigned char *digital_data_p) {
    return ioctl(
	device_handle,
	__RTD_ECAN_IOCTL__WRITE_DIGITAL_IO,
	digital_data_p
    );
}


int rtd_ecan_load_port_bit_dir(
    int device_handle,
    const rtd_ecan_load_port_bit_dir_t *direction_p
) {
    return ioctl(
	device_handle,
	__RTD_ECAN_IOCTL__LOAD_PORT_BIT_DIR,
	direction_p
    );
}


int rtd_ecan_allow_buffer_overwrite(int device_handle, unsigned char allow) {
    return ioctl(
	device_handle,
	__RTD_ECAN_IOCTL__ALLOW_BUFFER_OVERWRITE,
	allow
    );
}


// Testing of ECAN board
// Returns success flag, see 'errno' otherwise
bool Ecan_TestBoard(HANDLE hDevice)
{
    return !rtd_ecan_test(hDevice);
}


// Set operating mode
// Returns success flag, see 'errno' otherwise
bool Ecan_StartBoard(HANDLE hDevice)
{
    return !rtd_ecan_start(hDevice);
}


// Set reset mode
// Returns success flag, see 'errno' otherwise
bool Ecan_StopBoard(HANDLE hDevice)
{
    return !rtd_ecan_stop(hDevice);
}


// Set CAN controller's RAM area from user's buffer
// StartAddress, Count - CAN RAM addr/count
// Buffer - user's buffer, BuffSize - user's buffer size
// Returns real amount of written octets, 0 on errors (see 'errno')
size_t Ecan_SetBuffer(
    HANDLE hDevice,
    size_t StartAddress,
    size_t Count,
    const void *Buffer_p,
    size_t BuffSize
) {
    int rc;

    if (BuffSize < Count) {
	errno = EFAULT;
	raise(SIGSEGV);
	return 0;
    }

    rc = rtd_ecan_set_ram(hDevice, StartAddress, Count, Buffer_p);
    return rc < 0 ? 0 : Count;
}


// Get CAN controller's RAM area into user's buffer
// StartAddress, Count - CAN RAM addr/count
// Buffer - user's buffer, BuffSize - user's buffer size
// Returns real amount of readed octets, 0 on errors (see 'errno')
size_t Ecan_GetBuffer(
    HANDLE hDevice,
    size_t StartAddress,
    size_t Count,
    void *Buffer_p,
    size_t BuffSize
) {
    int rc;

    if (BuffSize < Count) {
	errno = EFAULT;
	raise(SIGSEGV);
	return 0;
    }

    rc = rtd_ecan_get_ram(hDevice, StartAddress, Count, Buffer_p);
    return rc < 0 ? 0 : Count;
}


// Returns success flag, see 'errno' otherwise
bool Ecan_SetLeds(HANDLE hDevice, bool RedLed, bool GreenLed)
{
    int rc;

    rc = rtd_ecan_set_leds(
	hDevice,
	(RedLed?RTD_ECAN_LED_RED:0) | (GreenLed?RTD_ECAN_LED_GREEN:0)
    );

    return (rc < 0 && errno == ENOTSUP) ? true : !rc;
}


// Returns success flag, see 'errno' otherwise
bool Ecan_SendCommand(
    HANDLE hDevice,
    bool TR,
    bool RRB,
    bool AT,
    bool CDO,
    bool SRR
) {
    struct rtd_ecan_send_command command;

    command.TR  = TR;
    command.RRB = RRB;
    command.AT  = AT;
    command.CDO = CDO;
    command.SRR = SRR;

    return !rtd_ecan_send_command(hDevice, &command);
}


// Open device
// DevNum   - board (minor) number
// Ecan1000 - selects driver name ECAN1000/ECAN527
// Returns device handle or -1 on errors (see 'errno')
HANDLE Ecan_CreateHandle(size_t DevNum, bool Ecan1000)
{
    char devname[RTD_ECAN_DEVICE_MAX_NAME_LENGTH];

    sprintf(devname, "%s%u-%u",
	    RTD_ECAN_DEVICE_NAME_BASE,
	    Ecan1000 ? RTD_ECAN1000_MAGIC_NUMBER : RTD_ECAN527_MAGIC_NUMBER,
	    DevNum );

    return open(devname, O_RDWR);
}


// Returns board magical number (527 for ECAN527, 1000 for ECAN1000)
// or 0 on errors (see 'errno')
ulong Ecan_GetBoardName(HANDLE hDevice)
{
    ssize_t rc;

    rc = rtd_ecan_get_board_name(hDevice);
    return rc < 0 ? 0 : rc;
}


// hardware-specific values provided by user
// Returns success flag, see 'errno' otherwise
bool Ecan_BusConfig(
    HANDLE hDevice,
    u8_t BusTiming0,
    u8_t BusTiming1,
    u8_t ClockOut,
    u8_t BusConfig
) {
    return !rtd_ecan_set_bus_config(
	hDevice,
	BusTiming0,
	BusTiming1,
	ClockOut,
	BusConfig
    );
}


// Set interrupts mask and default max queue sizes
// Returns success flag, see 'errno' otherwise
bool Ecan_SetupBoard(
    HANDLE hDevice,
    bool ReceiveIntEn,
    bool ErrorIntEn,
    bool TransmitIntEn,
    bool BusErrorIntEn,
    bool DataOverrunIntEn,
    bool ArbitrationLostIntEn,
    bool ErrorPassiveIntEn,
    bool WakeUpIntEn,
    unsigned long int RxSize,
    unsigned long int TxSize
) {
    uint events_mask =
	  (        ReceiveIntEn ? RTD_ECAN_EVENT_RECEIVE          : 0)
	| (       TransmitIntEn ? RTD_ECAN_EVENT_TRANSMIT         : 0)
	| (          ErrorIntEn ? RTD_ECAN_EVENT_ERROR_WARN_LIMIT : 0)
	| (    DataOverrunIntEn ? RTD_ECAN_EVENT_DATA_OVERRUN     : 0)
	| (         WakeUpIntEn ? RTD_ECAN_EVENT_WAKE_UP          : 0)
	| (   ErrorPassiveIntEn ? RTD_ECAN_EVENT_ERROR_PASSIVE    : 0)
	| (ArbitrationLostIntEn ? RTD_ECAN_EVENT_ARBITRATION_LOST : 0)
	| (       BusErrorIntEn ? RTD_ECAN_EVENT_BUS_ERROR        : 0) ;

    int rc = rtd_ecan_set_events_mask(hDevice, events_mask);
    if (rc < 0) return false;

    /*
     * Set default receive queue size only if caller specified a non-default
     * value for queue size
     */

    if (RxSize != 0) {
	rc = rtd_ecan_set_rx_max_queue_size(hDevice, RxSize);
	if (rc < 0) {
	    return false;
	}
    }

    /*
     * Set default transmit queue size only if caller specified a non-default
     * value for queue size
     */

    if (TxSize != 0) {
	rc = rtd_ecan_set_tx_max_queue_size(hDevice, TxSize);
	if (rc < 0) {
	    return false;
	}
    }

    return true;
}


// Clear queues if requested and get current queue counts
// Returns success flag, see 'errno' otherwise
bool Ecan_GetQueuesCounts(
    HANDLE hDevice,
    ulong *TX_Count_p,
    ulong *RX_Count_p,
    bool ClearRX,
    bool ClearTX
) {
    int		rc;
    size_t	rxcnt;
    size_t	txcnt;
    uint	queue_flags;

    queue_flags = (
	(ClearRX ? RTD_ECAN_RX_QUEUE : 0)
	|
	(ClearTX ? RTD_ECAN_TX_QUEUE : 0)
    );

    /*
     * Avoid unnecesary system call if not clearing either queue
     */

    if (queue_flags != 0) {
	rc = rtd_ecan_clear_queues(hDevice, queue_flags);
	if (rc < 0) {
	    return !rc;
	}
    }

    rc = rtd_ecan_get_queues_counts(hDevice, &rxcnt, &txcnt);
    if (rc < 0)
    {
	if (TX_Count_p) *TX_Count_p = -1UL;
	if (RX_Count_p) *RX_Count_p = -1UL;
	return !rc;
    }

    if (TX_Count_p) *TX_Count_p = txcnt;
    if (RX_Count_p) *RX_Count_p = rxcnt;

    return !rc;
}


// Prepare message from receive queue head for access by other calls
// (if DontQueueUse == false),
// get message interrupt bits and current receive queue count (if requested)
// On errors returns 0 (see 'errno')
// Note that with this interface design it is impossible to separate
//   error condition from "no interrupts"
uint Ecan_GetInterrupts(HANDLE hDevice, ulong *QueueSize_p, bool DontQueueUse)
{
    uint events;
    size_t rx_queue_count;

    int rc = rtd_ecan_prepare_received_message(
	hDevice,
	&events,
	&rx_queue_count,
	DontQueueUse
    );

    if (rc < 0)
	events = 0;

    if (QueueSize_p)
	*QueueSize_p = rc < 0 ? 0ul : rx_queue_count;

    return events;
}


// Returns success flag, see 'errno' otherwise
bool Ecan_GetStatus(HANDLE hDevice, ECAN_STATUS_STRUCTURE *Status_p)
{
    struct rtd_ecan_status status;

    int rc = rtd_ecan_get_status(hDevice, &status, Status_p->DontQueueUse);

    Status_p->BusOff      = status.BusOff;
    Status_p->Warning     = status.Warning;
    Status_p->WakeUp      = status.WakeUp;
    Status_p->TXOK        = status.TXOK;
    Status_p->RXOK        = status.RXOK;
    Status_p->TS          = status.TS;
    Status_p->RS          = status.RS;
    Status_p->TBS         = status.TBS;
    Status_p->DOS         = status.DOS;
    Status_p->RBS         = status.RBS;
    Status_p->Arbitration = status.Arbitration;
    Status_p->ErrorCode   = status.ErrorCode;

    return !rc;
}


// Returns success flag, see 'errno' otherwise
bool Ecan_GetMessage (HANDLE hDevice, ECAN_MESSAGE_STRUCTURE *message_p)
{
    struct rtd_ecan_message _msg;

    _msg.Channel = message_p->Channel;

    int rc = rtd_ecan_recv_message(hDevice, &_msg, message_p->DontQueueUse);

    message_p->ID_0 = _msg.ID[0];
    message_p->ID_1 = _msg.ID[1];
    message_p->ID_2 = _msg.ID[2];
    message_p->ID_3 = _msg.ID[3];
    message_p->DataLength = _msg.DataLength;
    memcpy(message_p->Data, _msg.Data, sizeof(_msg.Data));
    message_p->Extended = _msg.Extended; message_p->Remote = _msg.Remote;
    message_p->NextMsg = _msg.NextMsg;
    message_p->Channel = _msg.Channel;

    return !rc;
}


// Returns success flag, see 'errno' otherwise
bool Ecan_SendMessage(HANDLE hDevice, ECAN_MESSAGE_STRUCTURE *message_p)
{
    struct rtd_ecan_message _msg;

    _msg.Channel = message_p->Channel;
    _msg.ID[0] = message_p->ID_0;
    _msg.ID[1] = message_p->ID_1;
    _msg.ID[2] = message_p->ID_2;
    _msg.ID[3] = message_p->ID_3;
    _msg.DataLength = message_p->DataLength;
    memcpy(_msg.Data, message_p->Data, sizeof(message_p->Data));
    _msg.Extended = message_p->Extended; _msg.Remote = message_p->Remote;

    int rc = rtd_ecan_send_message(hDevice, &_msg, message_p->DontQueueUse);

    message_p->NextMsg = _msg.NextMsg;

    return !rc;
}


// ECAN527 only
// Returns success flag, see 'errno' otherwise
bool Ecan_MessageObjectSetup(
    HANDLE hDevice,
    ECAN_MESSAGE_OBJECT_SETUP_STRUCTURE *object_p
) {
    struct rtd_ecan_msg_obj_setup _msg;

    _msg.State   = object_p->State;
    _msg.Channel = object_p->Channel;

    _msg.ID[0]   = object_p->ID_0;
    _msg.ID[1]   = object_p->ID_1;
    _msg.ID[2]   = object_p->ID_2;
    _msg.ID[3]   = object_p->ID_3;

    _msg.Valid        = object_p->Valid;
    _msg.Extended     = object_p->Extended;
    _msg.RXIE         = object_p->RXIE;
    _msg.TXIE         = object_p->TXIE;

    _msg.MakeDefault  = object_p->MakeDefault;

    int rc = rtd_ecan_setup_message_object(
	hDevice,
	&_msg,
       	object_p->DontQueueUse
    );
    return (rc < 0 && errno == ENOTSUP) ? true : !rc;
}


// Returns success flag, see 'errno' otherwise
bool Ecan_SetFilter(HANDLE hDevice, const ECAN_FILTER_STRUCTURE *filter_p)
{
    const struct rtd_ecan_filter filter =
    {
	{ filter_p->AC0, filter_p->AC1, filter_p->AC2, filter_p->AC3 },
	{ filter_p->AM0, filter_p->AM1, filter_p->AM2, filter_p->AM3 },

	{ filter_p->ME0, filter_p->ME1, filter_p->ME2, filter_p->ME3 },
	{ filter_p->MM0, filter_p->MM1, filter_p->MM2, filter_p->MM3 },

	filter_p->DualFilter,
	filter_p->MMIsExtended
    };

    return !rtd_ecan_set_filter(hDevice, &filter, filter_p->DontQueueUse);
}


/******************************************************************************
 * Ecan_ReadDigitalIO()                                                       *
 *                                                                            *
 *  Purpose:                                                                  *
 *	Read whatever value happens to be currently available on an           *
 *	interface's digital I/O port.  ECAN527 only.                          *
 *                                                                            *
 *  Parameters:                                                               *
 *	device_handle ==> Device handle from Ecan_CreateHandle() or file      *
 *			  descriptor from open(2) system call.                *
 *	digital_data_p => Address of user buffer in which to store data.      *
 *                                                                            *
 *  Return value:                                                             *
 *	0 on success.                                                         *
 *                                                                            *
 *	-1 on failure.  Please see the description of                         *
 *	rtd_ecan_read_digital_io() for information on possible values errno   *
 *	may have in this case.                                                *
 ******************************************************************************/

int Ecan_ReadDigitalIO(HANDLE device_handle, unsigned char *digital_data_p) {
    return rtd_ecan_read_digital_io(device_handle, digital_data_p);
}


/******************************************************************************
 * Ecan_WriteDigitalIO()                                                      *
 *                                                                            *
 *  Purpose:                                                                  *
 *	Write a value to an interface's digital I/O port.  ECAN527 only.      *
 *                                                                            *
 *  Parameters:                                                               *
 *	device_handle ==> Device handle from Ecan_CreateHandle() or file      *
 *			  descriptor from open(2) system call.                *
 *	digital_data_p => Address of user buffer containing data to write.    *
 *                                                                            *
 *  Return value:                                                             *
 *	0 on success.                                                         *
 *                                                                            *
 *	-1 on failure.  Please see the description of                         *
 *	rtd_ecan_write_digital_io() for information on possible values errno  *
 *	may have in this case.                                                *
 ******************************************************************************/
int Ecan_WriteDigitalIO(HANDLE device_handle, unsigned char *digital_data_p) {
    return rtd_ecan_write_digital_io(device_handle, digital_data_p);
}


/******************************************************************************
 * Ecan_LoadPortBitDir()                                                      *
 *                                                                            *
 *  Purpose:                                                                  *
 *	Programs the direction (input or output) of each bit in the digital   *
 *	I/O port.                                                             *
 *                                                                            *
 *  Parameters:                                                               *
 *	device_handle ==> Device handle from Ecan_CreateHandle() or file      *
 *			  descriptor from open(2) system call.                *
 *	bit7 ===========> Direction for bit 7.                                *
 *	bit6 ===========> Direction for bit 6.                                *
 *	bit5 ===========> Direction for bit 5.                                *
 *	bit4 ===========> Direction for bit 4.                                *
 *	bit3 ===========> Direction for bit 3.                                *
 *	bit2 ===========> Direction for bit 2.                                *
 *	bit1 ===========> Direction for bit 1.                                *
 *	bit0 ===========> Direction for bit 0.                                *
 *	    For bit7 through bit0, a value of false (0) means input and a     *
 *	    value of true (1) means output.  By default, each bit is set to   *
 *	    input.                                                            *
 *                                                                            *
 *  Return value:                                                             *
 *	0 on success.                                                         *
 *                                                                            *
 *	-1 on failure.  Please see the description of                         *
 *	rtd_ecan_load_port_bit_dir() for information on possible values errno *
 *	may have in this case.                                                *
 ******************************************************************************/

int Ecan_LoadPortBitDir(
    HANDLE device_handle,
    bool bit7,
    bool bit6,
    bool bit5,
    bool bit4,
    bool bit3,
    bool bit2,
    bool bit1,
    bool bit0
) {
    rtd_ecan_load_port_bit_dir_t	direction;

    direction.bit7 = bit7;
    direction.bit6 = bit6;
    direction.bit5 = bit5;
    direction.bit4 = bit4;
    direction.bit3 = bit3;
    direction.bit2 = bit2;
    direction.bit1 = bit1;
    direction.bit0 = bit0;

    return rtd_ecan_load_port_bit_dir(device_handle, &direction);
}


/******************************************************************************
 * Ecan_AllowBufferOverwrite()                                                *
 *                                                                            *
 *  Purpose:                                                                  *
 *	Instruct driver how to process receive queue overruns.                *
 *                                                                            *
 *  Parameters:                                                               *
 *	device_handle => Device handle from Ecan_CreateHandle() or file       *
 *			 descriptor from open(2) system call.                 *
 *	allow =========> Flag to indicate whether or not to overwrite receive *
 *			 queue contents on overrun.  A value of false means   *
 *			 do not overwrite the oldest queue message with a new *
 *			 message and instead try to put an special overrun    *
 *			 message in the queue. A value of true means          *
 *			 overwrite the oldest queue message with a new        *
 *			 message and do not put a special overrun message in  *
 *			 the queue.                                           *
 *                                                                            *
 *  Return value:                                                             *
 *	0 on success.                                                         *
 *                                                                            *
 *	-1 on failure.  Please see the description of                         *
 *	rtd_ecan_allow_buffer_overwrite() for information on possible values  *
 *	errno may have in this case.                                          *
 ******************************************************************************/

int Ecan_AllowBufferOverwrite(HANDLE device_handle, bool allow) {
    return rtd_ecan_allow_buffer_overwrite(device_handle, allow);
}


/******************************************************************************
Ecan_SetBitRate()

    Purpose:
        Set CAN bus bit rate.

    Parameters:
        device_handle => Device handle from Ecan_CreateHandle() or file
                         descriptor from open() system call.
        BitRate =======> CAN bus bit rate to set.  For a list of valid values,
                         please see the BitRates enumeration in
                         include/ecanioctl.h.

    Return Value:
        true
            Success.

        false
            Failure with errno set as follows:
                EINVAL
                    BitRate is not valid.

            Please see the description of Ecan_BusConfig() for information on
            other possible values errno may have in this case.
 ******************************************************************************/

bool Ecan_SetBitRate(HANDLE device_handle, BitRates BitRate) {
    switch (BitRate) {
	case R1000000:
	    return Ecan_BusConfig(device_handle, 0, 0x14, 0, 0xff);
	    break;

	case R800000:
	    return Ecan_BusConfig(device_handle, 0, 0x16, 0, 0xff);
	    break;

	case R500000:
	    return Ecan_BusConfig(device_handle, 0, 0x1C, 0, 0xff);
	    break;

	case R400000:
	    return Ecan_BusConfig(device_handle, 0, 0x2F, 0, 0xff);
	    break;

	case R250000:
	    return Ecan_BusConfig(device_handle, 0x01, 0x1C, 0, 0xff);
	    break;

	case R200000:
	    return Ecan_BusConfig(device_handle, 0x01, 0x2F, 0, 0xff);
	    break;

	case R160000:
	    return Ecan_BusConfig(device_handle, 0x01, 0x7F, 0, 0xff);
	    break;

	case R125000:
	    return Ecan_BusConfig(device_handle, 0x03, 0x1C, 0, 0xff);
	    break;

	case R100000:
	    return Ecan_BusConfig(device_handle, 0xC3, 0xBE, 0, 0xff);
	    break;

	case R80000:
	    return Ecan_BusConfig(device_handle, 0xC4, 0xBE, 0, 0xff);
	    break;

	case R62500:
	    return Ecan_BusConfig(device_handle, 0xC7, 0xBA, 0, 0xff);
	    break;

	case R50000:
	    return Ecan_BusConfig(device_handle, 0xC7, 0xBE, 0, 0xff);
	    break;

	case R40000:
	    return Ecan_BusConfig(device_handle, 0xC9, 0xBE, 0, 0xff);
	    break;

	case R31250:
	    return Ecan_BusConfig(device_handle, 0xCF, 0xBA, 0, 0xff);
	    break;

	case R25000:
	    return Ecan_BusConfig(device_handle, 0xCF, 0xBE, 0, 0xff);
	    break;

	case R20000:
	    return Ecan_BusConfig(device_handle, 0xD3, 0xBE, 0, 0xff);
	    break;

	case R16000:
	    return Ecan_BusConfig(device_handle, 0xD8, 0xBE, 0, 0xff);
	    break;

	case R15625:
	    return Ecan_BusConfig(device_handle, 0xDF, 0xBA, 0, 0xff);
	    break;

	case R12500:
	    return Ecan_BusConfig(device_handle, 0xDF, 0xBE, 0, 0xff);
	    break;

	case R10000:
	    return Ecan_BusConfig(device_handle, 0xE7, 0xBE, 0, 0xff);
	    break;

	case R8000:
	    return Ecan_BusConfig(device_handle, 0xF1, 0xBE, 0, 0xff);
	    break;

	case R7813:		// (actually 7812.5)
	    return Ecan_BusConfig(device_handle, 0xFF, 0xBA, 0, 0xff);
	    break;

	case R6150:
	    return Ecan_BusConfig(device_handle, 0xFF, 0xBE, 0, 0xff);
	    break;

	case R5000:
	    return Ecan_BusConfig(device_handle, 0xFF, 0xFF, 0, 0xff);
	    break;

	default:
	    errno = EINVAL;
	    return false;
	    break;
    }
}


/******************************************************************************
Ecan_SetSingleFilterStandard()

    Purpose:
        For the ECAN1000 only, set up a filter for standard frames in single
        filter mode.

    Parameters:
        device_handle => Device handle from Ecan_CreateHandle() or file
                         descriptor from open() system call.
        ID_ACR ========> 11-bit Acceptance Code for message ID.
        ID_AMR ========> 11-bit Acceptance Mask for message ID.
        RTR_ACR =======> 1-bit Acceptance Code for Remote Transmission Request
                         bit.
        RTR_AMR =======> 1-bit Acceptance Mask for Remote Transmission Request
                         bit.
        Data_ACR ======> 16-bit Acceptance Code for first 16 bits of message
                         data.
        Data_AMR ======> 16-bit Acceptance Mask for first 16 bits of message
                         data.

    Return Value:
        true
            Filter set succeeded.

        false
            Filter set failed.  Please see the description of Ecan_SetFilter()
            for information on possible values errno may have in this case.

    NOTE:
        Unless you feel adventurous enough to undertake determining the exact
        bit patterns to set in the filter structure, do not use
        Ecan_SetFilter() or rtd_ecan_set_filter() to set filters on the
        ECAN1000.  Use this function instead.
 ******************************************************************************/

bool Ecan_SetSingleFilterStandard(
    HANDLE device_handle,
    uint ID_ACR,
    uint ID_AMR,
    uint RTR_ACR,
    uint RTR_AMR,
    uint Data_ACR,
    uint Data_AMR
) {
    ECAN_FILTER_STRUCTURE	filter;
    uint			byte1;
    uint			byte2;

    /*
     * Encode message data bytes 1 and 2 into the Acceptance Code and
     * Acceptance Mask Registers
     */

    filter.AC2 = (Data_ACR & 0xFF);
    filter.AC3 = (Data_ACR >> 8);

    filter.AM2 = (Data_AMR & 0xFF);
    filter.AM3 = (Data_AMR >> 8);

    /*
     * Encode message ID into the Acceptance Code and Acceptance Mask Registers
     */

    byte1 = (ID_ACR & 0xFF);
    byte2 = (ID_ACR >> 8);
    filter.AC1 = ((byte1 & 7) << 5);
    filter.AC0 = ((byte1 & 0xF8) >> 3);
    filter.AC0 |= ((byte2 & 7) << 5);

    byte1 = (ID_AMR & 0xFF);
    byte2 = (ID_AMR >> 8);
    filter.AM1 = ((byte1 & 7) << 5);
    filter.AM0 = ((byte1 & 0xF8) >> 3);
    filter.AM0 |= ((byte2 & 7) << 5);

    /*
     * Encode Remote Transmission Request bit into the Acceptance Code and
     * Acceptance Mask Registers
     */

    filter.AC1 |= ((RTR_ACR & 1) << 4);
    filter.AM1 |= ((RTR_AMR & 1) << 4);

    /*
     * Bits 0 through 3 in Acceptance Mask Register 1 must be set to 1, i.e.
     * don't care
     */

    filter.AM1 |= 0xF;

    filter.DualFilter = false;

    return Ecan_SetFilter(device_handle, &filter);
}


/******************************************************************************
Ecan_SetSingleFilterExtended()

    Purpose:
        For the ECAN1000 only, set up a filter for extended frames in single
        filter mode.

    Parameters:
        device_handle => Device handle from Ecan_CreateHandle() or file
                         descriptor from open() system call.
        ID_ACR ========> 29-bit Acceptance Code for message ID.
        ID_AMR ========> 29-bit Acceptance Mask for message ID.
        RTR_ACR =======> 1-bit Acceptance Code for Remote Transmission Request
                         bit.
        RTR_AMR =======> 1-bit Acceptance Mask for Remote Transmission Request
                         bit.

    Return Value:
        true
            Filter set succeeded.

        false
            Filter set failed.  Please see the description of Ecan_SetFilter()
            for information on possible values errno may have in this case.

    NOTE:
        Unless you feel adventurous enough to undertake determining the exact
        bit patterns to set in the filter structure, do not use
        Ecan_SetFilter() or rtd_ecan_set_filter() to set filters on the
        ECAN1000.  Use this function instead.
 ******************************************************************************/

bool Ecan_SetSingleFilterExtended(
    HANDLE device_handle,
    uint ID_ACR,
    uint ID_AMR,
    uint RTR_ACR,
    uint RTR_AMR
) {
    ECAN_FILTER_STRUCTURE	filter;
    uint8_t			ACR0;
    uint8_t			ACR1;
    uint8_t			ACR2;
    uint8_t			ACR3;
    uint8_t			AMR0;
    uint8_t			AMR1;
    uint8_t			AMR2;
    uint8_t			AMR3;

    /*
     * Encode Acceptance Code Register bits
     */

    ACR3 = (uint8_t) (ID_ACR & 0xFF);
    ID_ACR >>= 8;
    ACR2 = (uint8_t) (ID_ACR & 0xFF);
    ID_ACR >>= 8;
    ACR1 = (uint8_t) (ID_ACR & 0xFF);
    ID_ACR >>= 8;
    ACR0 = (uint8_t) (ID_ACR & 0xFF);

    EncodeMessageID(&ACR0, &ACR1, &ACR2, &ACR3, true);

    filter.AC0 = ACR0;
    filter.AC1 = ACR1;
    filter.AC2 = ACR2;
    filter.AC3 = ACR3;

    /*
     * Encode Acceptance Mask Register bits
     */

    AMR3 = (uint8_t) (ID_AMR & 0xFF);
    ID_AMR >>= 8;
    AMR2 = (uint8_t) (ID_AMR & 0xFF);
    ID_AMR >>= 8;
    AMR1 = (uint8_t) (ID_AMR & 0xFF);
    ID_AMR >>= 8;
    AMR0 = (uint8_t) (ID_AMR & 0xFF);

    EncodeMessageID(&AMR0, &AMR1, &AMR2, &AMR3, true);

    filter.AM0 = AMR0;
    filter.AM1 = AMR1;
    filter.AM2 = AMR2;
    filter.AM3 = AMR3;

    /*
     * Encode the Remote Transmission Request bit into the Acceptance Code and
     * Acceptance Mask Registers
     */

    filter.AC3 |= ((RTR_ACR & 1) << 2);
    filter.AM3 |= ((RTR_AMR & 1) << 2);

    /*
     * Bits 0 and 1 in Acceptance Mask Register 3 must be set to 1, i.e.
     * don't care
     */

    filter.AM3 |= 3;

    filter.DualFilter = false;

    return Ecan_SetFilter(device_handle, &filter);
}


/******************************************************************************
Ecan_SetDualFilterStandard()

    Purpose:
        For the ECAN1000 only, set up a filter for standard frames in dual
        filter mode.

    Parameters:
        device_handle => Device handle from Ecan_CreateHandle() or file
                         descriptor from open() system call.
        ID_ACR1 =======> 11-bit Acceptance Code 1 for message ID.
        ID_AMR1 =======> 11-bit Acceptance Mask 1 for message ID.
        ID_ACR2 =======> 11-bit Acceptance Code 2 for message ID.
        ID_AMR2 =======> 11-bit Acceptance Mask 2 for message ID.
        RTR_ACR1 ======> 1-bit Acceptance Code 1 for Remote Transmission
                         Request bit.
        RTR_AMR1 ======> 1-bit Acceptance Mask 1 for Remote Transmission
                         Request bit.
        RTR_ACR2 ======> 1-bit Acceptance Code 2 for Remote Transmission
                         Request bit.
        RTR_AMR2 ======> 1-bit Acceptance Mask 2 for Remote Transmission
                         Request bit.
        Data_ACR ======> 8-bit Acceptance Code for first 8 bits of message
                         data.
        Data_AMR ======> 8-bit Acceptance Mask for first 8 bits of message
                         data.

    Return Value:
        true
            Filter set succeeded.

        false
            Filter set failed.  Please see the description of Ecan_SetFilter()
            for information on possible values errno may have in this case.

    NOTE:
        Unless you feel adventurous enough to undertake determining the exact
        bit patterns to set in the filter structure, do not use
        Ecan_SetFilter() or rtd_ecan_set_filter() to set filters on the
        ECAN1000.  Use this function instead.
 ******************************************************************************/

bool Ecan_SetDualFilterStandard(
    HANDLE device_handle,
    uint ID_ACR1,
    uint ID_AMR1,
    uint ID_ACR2,
    uint ID_AMR2,
    uint RTR_ACR1,
    uint RTR_AMR1,
    uint RTR_ACR2,
    uint RTR_AMR2,
    uint Data_ACR,
    uint Data_AMR
) {
    ECAN_FILTER_STRUCTURE	filter;
    uint			byte1;
    uint			byte2;

    /*
     * Encode message ID into Acceptance Code and Acceptance Mask Registers
     * for filter 1
     */

    byte1 = (ID_ACR1 & 0xFF);
    byte2 = (ID_ACR1 >> 8);
    filter.AC1 = ((byte1 & 7) << 5);
    filter.AC0 = ((byte1 & 0xF8) >> 3);
    filter.AC0 |= ((byte2 & 7) << 5);

    /*
     * Encode message ID into Acceptance Code and Acceptance Mask Registers
     * for filter 2
     */

    byte1 = (ID_ACR2 & 0xFF);
    byte2 = (ID_ACR2 >> 8);
    filter.AC3 = ((byte1 & 7) << 5);
    filter.AC2 = ((byte1 & 0xF8) >> 3);
    filter.AC2 |= ((byte2 & 7) << 5);

    /*
     * Encode message data byte into Acceptance Code and Acceptance Mask
     * Registers for filter 1
     */

    byte1 = (ID_AMR1 & 0xFF);
    byte2 = (ID_AMR1 >> 8);
    filter.AM1 = ((byte1 & 7) << 5);
    filter.AM0 = ((byte1 & 0xf8) >> 3);
    filter.AM0 |= ((byte2 & 7) << 5);

    /*
     * Encode message data byte into Acceptance Code and Acceptance Mask
     * Registers for filter 2
     */

    byte1 = (ID_AMR2 & 0xFF);
    byte2 = (ID_AMR2 >> 8);
    filter.AM3 = ((byte1 & 7) << 5);
    filter.AM2 = ((byte1 & 0xf8) >> 3);
    filter.AM2 |= ((byte2 & 7) << 5);

    /*
     * Encode Remote Transmission Request bit into Acceptance Code and
     * Acceptance Mask Registers for filter 1
     */

    filter.AC1 |= ((RTR_ACR1 & 1) << 4);
    filter.AM1 |= ((RTR_AMR1 & 1) << 4);

    /*
     * Encode Remote Transmission Request bit into Acceptance Code and
     * Acceptance Mask Registers for filter 2
     */

    filter.AC3 |= ((RTR_ACR2 & 1) << 4);
    filter.AM3 |= ((RTR_AMR2 & 1) << 4);

    /*
     * Encode message data byte into Acceptance Code and Acceptance Mask
     * Registers for filter 1
     */

    filter.AC3 |= (Data_ACR & 0xF);
    filter.AC1 |= ((Data_ACR >> 4) & 0xF);
    filter.AM3 |= (Data_AMR & 0xF);
    filter.AM1 |= ((Data_AMR >> 4) & 0xF);


    filter.DualFilter = true;

    return Ecan_SetFilter(device_handle, &filter);
}


/******************************************************************************
Ecan_SetDualFilterExtended()

    Purpose:
        For the ECAN1000 only, set up a filter for extended frames in dual
        filter mode.

    Parameters:
        device_handle => Device handle from Ecan_CreateHandle() or file
                         descriptor from open() system call.
        ID_ACR1 =======> 16-bit Acceptance Code 1 for message ID.
        ID_AMR1 =======> 16-bit Acceptance Mask 1 for message ID.
        ID_ACR2 =======> 16-bit Acceptance Code 2 for message ID.
        ID_AMR2 =======> 16-bit Acceptance Mask 2 for message ID.

    Return Value:
        true
            Filter set succeeded.

        false
            Filter set failed.  Please see the description of Ecan_SetFilter()
            for information on possible values errno may have in this case.

    NOTE:
        Unless you feel adventurous enough to undertake determining the exact
        bit patterns to set in the filter structure, do not use
        Ecan_SetFilter() or rtd_ecan_set_filter() to set filters on the
        ECAN1000.  Use this function instead.
 ******************************************************************************/

bool Ecan_SetDualFilterExtended(
    HANDLE device_handle,
    uint ID_ACR1,
    uint ID_AMR1,
    uint ID_ACR2,
    uint ID_AMR2
) {
    ECAN_FILTER_STRUCTURE	filter;
    uint			byte1;
    uint			byte2;

    /*
     * Encode message ID into Acceptance Code Register for filter 1
     */

    byte1 = (ID_ACR1 & 0xFF);
    byte2 = (ID_ACR1 >> 8);
    filter.AC0 = byte2;
    filter.AC1 = byte1;

    /*
     * Encode message ID into Acceptance Mask Register for filter 1
     */

    byte1 = (ID_AMR1 & 0xFF);
    byte2 = (ID_AMR1 >> 8);
    filter.AM0 = byte2;
    filter.AM1 = byte1;

    /*
     * Encode message ID into Acceptance Code Register for filter 2
     */

    byte1 = (ID_ACR2 & 0xFF);
    byte2 = (ID_ACR2 >> 8);
    filter.AC2 = byte2;
    filter.AC3 = byte1;

    /*
     * Encode message ID into Acceptance Mask Register for filter 2
     */

    byte1 = (ID_AMR2 & 0xFF);
    byte2 = (ID_AMR2 >> 8);
    filter.AM2 = byte2;
    filter.AM3 = byte1;

    filter.DualFilter = true;

    return Ecan_SetFilter(device_handle, &filter);
}
#endif
